package com.webex.ta.hydra.function;

import com.webex.ta.hydra.exceptions.InvalidVariableException;
import com.webex.ta.hydra.function.CompoundVariable;
import com.webex.ta.hydra.function.Function;

import java.io.IOException;
import java.io.StringReader;
import java.util.LinkedList;

/**
 * Created by IntelliJ IDEA.
 * User: vegaz
 * Date: 2010-8-30
 * Time: 13:27:10
 * To change this template use File | Settings | File Templates.
 */
public class FunctionParser {
    public static LinkedList compileString(String value) throws InvalidVariableException {
		StringReader reader = new StringReader(value);
		LinkedList result = new LinkedList();
		StringBuffer buffer = new StringBuffer();
		char previous = ' ';
		char[] current = new char[1];
		try {
			while (reader.read(current) == 1) {
//				if (current[0] == '\\') {
//					previous = current[0];
//					if (reader.read(current) == 0) {
//						break;
//					}
////					if (current[0] != '$' && current[0] != ',' && current[0] != '\\') {
//                    if (current[0] != '$' && current[0] != ',') {
//                        buffer.append(previous);
//					}
//					previous = ' ';
//					buffer.append(current[0]);
//					continue;
//				} else if (current[0] == '{' && previous == '$') {
                if (current[0] == '{' && previous == '$') {
                    buffer.deleteCharAt(buffer.length() - 1);
					if (buffer.length() > 0) {
						result.add(buffer.toString());
						buffer.setLength(0);
					}
					result.add(makeFunction(reader));
					previous = ' ';
				} else {
					buffer.append(current[0]);
					previous = current[0];
				}
			}
			if (buffer.length() > 0) {
				result.add(buffer.toString());
			}
		} catch (IOException e) {
//			log.error("Error parsing function: " + value, e);
			result.clear();
			result.add(value);
		}
		if (result.size() == 0) {
			result.add("");
		}
		return result;
	}


    static Object makeFunction(StringReader reader) throws InvalidVariableException {
		char[] current = new char[1];
		char previous = ' ';
		StringBuffer buffer = new StringBuffer();
		Object function;
        int varRecursion = 0;
        try {
			while (reader.read(current) == 1) {
				if (current[0] == '\\') {
					if (reader.read(current) == 0) {
						break;
					}
					previous = ' ';
					buffer.append(current[0]);
					continue;
				} else if (current[0] == '(' && previous != ' ') {
                    String funcName = buffer.toString();
					function = FunctionManager.getNamedFunction(funcName);
					buffer.setLength(0);
					if (function instanceof Function) {
						((Function) function).setParameters(parseParams(reader));
						if (reader.read(current) == 0 || current[0] != '}') {
                            reader.reset();// set to start of string
                            char []cb = new char[100];
                            reader.read(cb);// return deliberately ignored
							throw new InvalidVariableException
                            ("Expected } after "+funcName+" function call in "+new String(cb));
						}
//						if (function instanceof TestListener) {
//							StandardJMeterEngine.register((TestListener) function);
//						}
						return function;
					}
					continue;
				} else if (current[0] == '{' && previous == '$') {
                    varRecursion ++;
                    buffer.append(current[0]);
					previous = current[0];
                } else if (current[0] == '}' && varRecursion == 0) {
                    function = FunctionManager.getNamedFunction(buffer.toString());
                    buffer.setLength(0);
                    return function;
                } else if (current[0] == '}' && varRecursion > 0) {
                    buffer.append(current[0]);
					previous = current[0];
                    varRecursion--;
                } else {
					buffer.append(current[0]);
					previous = current[0];
				}
			}
		} catch (IOException e) {
			return null;
		}
		return buffer.toString();
	}


    static LinkedList<CompoundVariable> parseParams(StringReader reader) throws InvalidVariableException {
		LinkedList<CompoundVariable> result = new LinkedList<CompoundVariable>();
		StringBuffer buffer = new StringBuffer();
		char[] current = new char[1];
		char previous = ' ';
		int functionRecursion = 0;
		int parenRecursion = 0;
		try {
			while (reader.read(current) == 1) {
				if (current[0] == '\\') {
					buffer.append(current[0]);
					if (reader.read(current) == 0) {
						break;
					}
					previous = ' ';
					buffer.append(current[0]);
					continue;
				} else if (current[0] == ',' && functionRecursion == 0) {
					CompoundVariable param = new CompoundVariable();
					param.setParameter(buffer.toString());
					buffer.setLength(0);
					result.add(param);
				} else if (current[0] == ')' && functionRecursion == 0 && parenRecursion == 0) {
					CompoundVariable param = new CompoundVariable();
					param.setParameter(buffer.toString());
					buffer.setLength(0);
					result.add(param);
					return result;
				} else if (current[0] == '{' && previous == '$') {
					buffer.append(current[0]);
					previous = current[0];
					functionRecursion++;
				} else if (current[0] == '}' && functionRecursion > 0) {
					buffer.append(current[0]);
					previous = current[0];
					functionRecursion--;
				} else if (current[0] == ')' && functionRecursion == 0 && parenRecursion > 0) {
					buffer.append(current[0]);
					previous = current[0];
					parenRecursion--;
				} else if (current[0] == '(' && functionRecursion == 0) {
					buffer.append(current[0]);
					previous = current[0];
					parenRecursion++;
				} else {
					buffer.append(current[0]);
					previous = current[0];
				}
			}
		} catch (IOException e) {

		}

		CompoundVariable var = new CompoundVariable();
		var.setParameter(buffer.toString());
		result.add(var);
		return result;
	}
}
